<?php
declare (strict_types = 1);

namespace app\controller\admin;

use app\event\AdminActionEvent;
use app\model\AdminMenu;
use app\traits\MyControllerTrait;
use app\model\AdminPermission;
use Symfony\Component\EventDispatcher\EventDispatcher;
use think\exception\ValidateException;
use think\facade\Session;
use think\Request;
use think\facade\Db;
use think\facade\Log;
use app\validate\admin\AdminPermissionValidate;

class AdminPermissionController
{
    use MyControllerTrait;

    protected string $uri   = '/admin/permission';
    protected string $title = "访问权限";

    public function index(Request $request)
    {
        $data = [
            'title' => $this->title,
            'uri'   => $this->uri,
            'menus' => $this->getMenuNav($this->uri.'/'.__FUNCTION__),
        ];
        return view($this->uri.'/'.__FUNCTION__, $data);
    }// index() end

    public function show(Request $request)
    {
        $page  = $request->get('page/d', 1);
        $limit = $request->get('limit/d', 10);
        $title = $request->get('title', '');
        $uri   = $request->get('uri', '');
        $where = "";
        $raw   = [];
        $order = ['id', 'DESC'];

        if (strlen($title) > 0)
        {
            $where       .= " AND title = :title";
            $raw['title'] = "%{$title}%";
        }
        if (strlen($uri) > 0)
        {
            $where     .= " AND uri = :uri";
            $raw['uri'] = "%{$uri}%";
        }

        [$total, $data] = AdminPermission::searchForShow(AdminPermission::class, $where, $raw, $page, $limit, $order);
        foreach($data as $index => $permission){
            $data[$index]['pid'] = AdminPermission::whereRaw("id = :id", ['id' => $permission['pid']])->value("title") ?? "根目录";
        }
        return json(['code' => 0, 'message' => 'success', 'data' => $data, 'total' => $total]);
    }// show() end

    public function create(Request $request)
    {
        $data = [
            'title'     => $this->title,
            'uri'       => $this->uri,
            'pid'       => AdminPermission::where('pid', 0)->column('title', 'id'),
            'is_show'   => AdminMenu::FIELDS['is_show'],
            '__token__' => $request->buildToken()
        ];
        return view($this->uri.'/'.__FUNCTION__, $data);
    }// create() end

    public function edit(Request $request)
    {
        $id = $request->get('permission_id/d', 0);

        $adminPermission = AdminPermission::whereRaw("id = :id", ['id' => $id])->findOrEmpty();
        if ($adminPermission->isEmpty()) return json(['code' => 0, 'message' => "permission_id:{$id} 不存在"]);

        $data = [
            'title'         => $this->title,
            'uri'           => $this->uri,
            'pid'           => AdminPermission::where('pid', 0)->column('title', 'id'),
            'permission_id' => $id,
            'data'          => $adminPermission->toArray(),
            '__token__'     => $request->buildToken()
        ];
        return view($this->uri.'/'.__FUNCTION__, $data);
    }// edit() end

    public function store(Request $request)
    {
        $title  = $request->post('title', '');
        $uri    = $request->post('uri', '');
        $pid    = $request->post('pid/d', 0);

        /****** 参数校验 *********/
        $check_data = [
            'title' => $title,
            'uri'   => $uri,
            'pid'   => $pid
        ];
        try {
            validate(AdminPermissionValidate::class)->check($check_data);
        } catch (ValidateException $e){
            return json(['code' => 0, 'message' => $e->getError()]);
        }

        $permission = AdminPermission::whereRaw("title = :title OR uri = :uri", ['title' => $title, 'uri' => $uri])->findOrEmpty();
        // $title 或 $uri 去重
        if ($permission->isExists())
        {
            if ($permission->title === $title) return json(['code' => 0, 'message' => "{$title} 已存在"]);
            if ($permission->uri !== "#" && $permission->uri === $uri) return json(['code' => 0, 'message' => "{$uri} 已存在"]);
        }

        AdminPermission::generateLog($title, $uri, $pid, AdminPermission::generatePath($pid));
        // 设置角色权限缓存数据
        AdminRolePermission::setRolePermissionToCache(AdminPermission::getPermission());
        $data = [
            $this->getPermissionTitle($this->uri.'/'.__FUNCTION__),
            Session::get("admin_user.account"),
            $permission->toArray()
        ];
        (new EventDispatcher)->dispatch((new AdminActionEvent($request, $data)), AdminActionEvent::EVENT_NAME);
        return json(['code' => 1, 'message' => '成功']);
    }// store() end

    public function update(Request $request)
    {
        $id     = $request->put('permission_id/d', 0);
        $title  = $request->put('title');
        $uri    = $request->put('uri');
        $pid    = $request->put('pid/d', 0);

        /****** 参数校验 *********/
        $check_data = [
            'title' => $title,
            'uri'   => $uri,
            'pid'   => $pid
        ];
        try {
            validate(AdminPermissionValidate::class)->check($check_data);
        } catch (ValidateException $e){
            return json(['code' => 0, 'message' => $e->getError()]);
        }

        $permission = AdminPermission::whereRaw("id = :id", ['id' => $id])->findOrEmpty();
        if ($permission->isEmpty()) return json(['code' => 0, 'message' => "permission_id:{$id} 不存在"]);
        if ($permission->title === $title && $permission->uri === $uri && $permission->pid === $pid) return json(['code' => 1, 'message' => "成功"]);

        // $title 去重
        if ($permission->title !== $title)
        {
            $permission2 = AdminPermission::whereRaw("title = :title", ['title' => $title])->findOrEmpty();
            if ($permission2->isExists()) return json(['code' => 0, 'message' => "{$title} 已存在"]);
        }
        // $uri 去重
        if ($permission->uri !== $uri)
        {
            $permission3 = AdminPermission::whereRaw("uri = :uri", ['uri' => $uri])->findOrEmpty();
            if ($permission3->isExists()) return json(['code' => 0, 'message' => "{$uri} 已存在"]);
        }

        $permission->title  = $title;
        $permission->uri    = $uri;
        $permission->pid    = $pid;
        $permission->path   = AdminPermission::generatepath($pid);
        $permission->save();
        // 设置角色权限缓存数据
        AdminRolePermission::setRolePermissionToCache(AdminPermission::getPermission());
        $data = [
            $this->getPermissionTitle($this->uri.'/'.__FUNCTION__),
            Session::get("admin_user.account"),
            $permission->toArray()
        ];
        (new EventDispatcher)->dispatch((new AdminActionEvent($request, $data)), AdminActionEvent::EVENT_NAME);
        return json(['code' => 1, 'message' => '成功']);
    }// update() end

    public function destroy(Request $request)
    {
        $id = $request->delete('permission_id/d', 0);
        if (1 > $id) return json(['code' => 0, 'message' => '删除失败']);

        $permission = AdminPermission::whereRaw("id = :id", ['id' => $id])->findOrEmpty();
        if ($permission->isEmpty()) return json(['code' => 0, 'message' => "permission_id:{$id} 不存在"]);

        Db::startTrans();
        try {
            // 删除子目录
            AdminPermission::deleteChildPermission($permission->id);
            $permission->delete();
            Db::commit();
        } catch (\Exception $e){
            Db::rollback();
            $message = [
                'function'  => __CLASS__.'->'.__FUNCTION__.'():'.__LINE__,
                'error'     => $e->getMessage()
            ];
            Log::channel('admin-controller')->error(json_encode($message, JSON_UNESCAPED_UNICODE));
            return json(['code' => 0, 'message' => '失败']);
        }
        // 设置角色权限缓存数据
        AdminRolePermission::setRolePermissionToCache(AdminPermission::getPermission());

        $data = [
            $this->getPermissionTitle($this->uri.'/'.__FUNCTION__),
            Session::get("admin_user.account"),
            $permission->toArray()
        ];
        (new EventDispatcher)->dispatch((new AdminActionEvent($request, $data)), AdminActionEvent::EVENT_NAME);
        return json(['code' => 1, 'message' => '成功']);
    }// destroy() end
}
